// 流水线监听器单例实现
class PipelineListener {
    private static PipelineListener instance
    private def script
    private Map context = [:]
    private String currentStage
    private boolean initialized = false
    // 标记监听器是否已注册
    private boolean cmdListenerRegistered = false
    private boolean stageListenerRegistered = false

    // 私有构造函数确保单例
    private PipelineListener() {}

    // 获取单例实例
    static PipelineListener getInstance() {
        if (!instance) {
            instance = new PipelineListener()
        }
        return instance
    }

    // 初始化监听器（仅做参数注入，不立即注册拦截器）
    void init(def script, Map defaultParams = [:]) {
        if (initialized) return

        this.script = script
        this.initialized = true

        // 1. 自动注入基础参数（核心功能，不依赖Jenkins方法）
        context = [
            pipelineId: UUID.randomUUID().toString(),
            nodeIp: getNodeIp(),
            startTime: new Date(),
            prId: script.params.pr_id ?: "unknown",
            repoName: script.params.pr_repo_name ?: "loongeasy-cloud",
            branch: script.params.branch ?: "develop",
            buildNumber: script.env.BUILD_NUMBER ?: "unknown",
            jobName: script.env.JOB_NAME ?: "unknown",
            userId: script.env.BUILD_USER ?: "unknown"
        ]

        // 合并默认参数
        if (defaultParams) {
            context.putAll(defaultParams)
        }

        // 2. 不立即注册拦截器，改为在第一个命令执行前动态检测
        script.echo "监听器初始化完成 | 流水线ID: ${context.pipelineId} | 等待方法加载..."

        // 3. 启动后台检测线程，确保拦截器在方法可用后立即注册
        startListenerRegistrationDetector()
    }

    // 后台检测线程：循环检测Jenkins方法是否可用，可用后立即注册拦截器
    private void startListenerRegistrationDetector() {
        new Thread({
            try {
                // 最多检测10秒（避免无限循环）
                int maxAttempts = 20
                int attempt = 0

                while (attempt < maxAttempts && !cmdListenerRegistered) {
                    // 检测sh/bat方法是否可用
                    boolean shAvailable = script.respondsTo("sh")
                    boolean batAvailable = script.respondsTo("bat")
                    boolean stageAvailable = script.respondsTo("stage")

                    // 命令方法（sh/bat）任一可用即可注册命令拦截器
                    if ((shAvailable || batAvailable) && !cmdListenerRegistered) {
                        registerCommandListener()
                        cmdListenerRegistered = true
                        script.echo "命令拦截器注册成功（sh=${shAvailable}, bat=${batAvailable}）"
                    }

                    // stage方法可用则注册阶段拦截器
                    if (stageAvailable && !stageListenerRegistered) {
                        registerStageListener()
                        stageListenerRegistered = true
                        script.echo "阶段拦截器注册成功"
                    }

                    // 全部注册完成则退出检测
                    if (cmdListenerRegistered && stageListenerRegistered) {
                        script.echo "所有拦截器注册完成"
                        break
                    }

                    // 未完成则休眠500ms重试
                    Thread.sleep(500)
                    attempt++
                }

                // 检测超时处理
                if (!cmdListenerRegistered) {
                    script.echo "警告：命令拦截器注册超时，可能无法捕获日志"
                }
                if (!stageListenerRegistered) {
                    script.echo "警告：阶段拦截器注册超时，可能无法跟踪阶段状态"
                }
            } catch (Exception e) {
                script.echo "拦截器注册检测线程异常: ${e.message}"
            }
        }).start()
    }

    // 注册阶段监听器（确保stage方法可用后调用）
    private void registerStageListener() {
        try {
            def originalStage = script.stage
            // 重写stage方法，添加日志跟踪
            script.stage = { String name, Closure closure ->
                currentStage = name
                logToEs("开始阶段: ${name}", "INFO")

                try {
                    // 执行原始stage逻辑
                    originalStage.call(name, closure)
                    logToEs("完成阶段: ${name}", "INFO")
                } catch (Exception e) {
                    def errorMsg = e.message ?: "未知错误"
                    logToEs("阶段失败: ${name} - ${errorMsg}", "ERROR")
                    // 记录失败信息
                    context.failureStage = name
                    context.failureReason = errorMsg
                    throw e // 重新抛出，不阻断原有流水线逻辑
                }
            }
        } catch (Exception e) {
            script.echo "阶段拦截器注册失败: ${e.message}"
            stageListenerRegistered = false
        }
    }

    // 注册命令监听器（确保sh/bat方法可用后调用）
    private void registerCommandListener() {
        try {
            // 拦截sh命令（仅在方法可用时）
            if (script.respondsTo("sh")) {
                def originalSh = script.sh
                script.sh = { Object... args ->
                    // 未初始化或未注册则直接执行原始方法
                    if (!initialized || !cmdListenerRegistered) {
                        return originalSh.call(* args)
                    }

                    // 解析命令参数（兼容Map和String两种调用方式）
                    def cmd = parseCommand(args)
                    logToEs("执行Shell命令: ${cmd}", "INFO")

                    def output = new StringBuilder()
                    def error = new StringBuilder()

                    // 构建增强参数（重定向输出）
                    def enhancedArgs = buildEnhancedArgs(args, output, error)

                    // 执行原始命令并获取退出码
                    def exitCode = originalSh.call(* enhancedArgs)

                    // 处理执行结果
                    handleCommandResult("sh", cmd, exitCode, error, args)

                    // 返回结果（兼容returnOutput/returnStatus参数）
                    return isReturnOutput(args) ? output.toString() : exitCode
                }
            }

            // 拦截bat命令（仅在方法可用时，适配Windows）
            if (script.respondsTo("bat")) {
                def originalBat = script.bat
                script.bat = { Object... args ->
                    if (!initialized || !cmdListenerRegistered) {
                        return originalBat.call(* args)
                    }

                    def cmd = parseCommand(args)
                    logToEs("执行Bat命令: ${cmd}", "INFO")

                    def output = new StringBuilder()
                    def error = new StringBuilder()

                    def enhancedArgs = buildEnhancedArgs(args, output, error)
                    def exitCode = originalBat.call(* enhancedArgs)

                    handleCommandResult("bat", cmd, exitCode, error, args)

                    return isReturnOutput(args) ? output.toString() : exitCode
                }
            }
        } catch (Exception e) {
            script.echo "命令拦截器注册失败: ${e.message}"
            cmdListenerRegistered = false
        }
    }

    // 工具方法：解析命令内容（兼容Map和String参数）
    private String parseCommand(Object[] args) {
        if (args.length == 0) return ""
        if (args[0] instanceof Map) {
            return args[0].script ?: ""
        } else {
            return args[0] ?: ""
        }
    }

    // 工具方法：判断是否需要返回输出
    private boolean isReturnOutput(Object[] args) {
        if (args.length == 0) return false
        if (args[0] instanceof Map) {
            return args[0].returnOutput ?: false
        }
        return false
    }

    // 工具方法：判断是否忽略错误
    private boolean isReturnStatus(Object[] args) {
        if (args.length == 0) return false
        if (args[0] instanceof Map) {
            return args[0].returnStatus ?: false
        }
        return false
    }

    // 工具方法：构建增强参数（重定向stdout/stderr）
    private Object[] buildEnhancedArgs(Object[] args, StringBuilder output, StringBuilder error) {
        if (args.length == 0) return args

        def enhancedArgs = []
        if (args[0] instanceof Map) {
            // 复制原有参数，避免修改原始Map
            def argsMap = new HashMap(args[0])
            // 重定向输出
            argsMap.stdout = { line ->
                output.append(line).append("\n")
                logToEs("[STDOUT] ${line}", "INFO")
                // 执行原始stdout回调（如果有）
                if (args[0].stdout instanceof Closure) {
                    args[0].stdout.call(line)
                }
            }
            argsMap.stderr = { line ->
                error.append(line).append("\n")
                logToEs("[STDERR] ${line}", "WARN")
                // 执行原始stderr回调（如果有）
                if (args[0].stderr instanceof Closure) {
                    args[0].stderr.call(line)
                }
            }
            // 强制返回退出码（用于结果判断）
            argsMap.returnStatus = true
            enhancedArgs << argsMap
        } else {
            // String参数方式：构建Map参数
            enhancedArgs << [
                script: args[0],
                stdout: { line ->
                    output.append(line).append("\n")
                    logToEs("[STDOUT] ${line}", "INFO")
                },
                stderr: { line ->
                    error.append(line).append("\n")
                    logToEs("[STDERR] ${line}", "WARN")
                },
                returnStatus: true
            ]
        }
        return enhancedArgs
    }

    // 工具方法：处理命令执行结果
    private void handleCommandResult(String cmdType, String cmd, int exitCode, StringBuilder error, Object[] args) {
        if (exitCode == 0) {
            logToEs("${cmdType}命令执行成功: ${cmd}", "INFO")
        } else {
            def errorMsg = error.toString().take(200) ?: "退出码: ${exitCode}"
            logToEs("${cmdType}命令执行失败: ${cmd} | ${errorMsg}", "ERROR")
            // 如果未设置returnStatus，抛出异常（保持原有逻辑）
            if (!isReturnStatus(args)) {
                throw new Exception("${cmdType}命令执行失败: ${errorMsg}")
            }
        }
    }

    // 生成节点IP地址
    private String getNodeIp() {
        def randomNum = (Math.floor(Math.random() * 255) + 1) as Integer
        return "10.1.128.${randomNum}"
    }
    
    // 获取上下文参数
    def getContext() {
        return context
    }
    
    // 重置监听器（用于测试或特殊场景）
    void reset() {
        instance = null
    }
}

// 提供实例访问方法
def getInstance() {
    return PipelineListener.getInstance()
}

// 初始化方法 - 供流水线调用
def init(Map defaultParams = [:]) {
    getInstance().init(this, defaultParams)
}

// 获取上下文方法 - 供流水线调用
def getContext() {
    return getInstance().getContext()
}
